package fr.cephb.operonj.core.bio;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

public class Observed
	implements Serializable
	{
	private static final long serialVersionUID = 1L;
	static private final Pattern SPLIT=Pattern.compile("[/]");
	static private final Pattern BASES=Pattern.compile("[ATGC]+");
	static public final String LARGE_DELETION_FLAG="(LARGEDELETION)";
	static public final String LARGE_INSERTION_FLAG="(LARGEINSERTION)";
	static public final String HETEROZYGOUS="HETEROZYGOUS";
	private String content;
	public Observed(String s)
		{
		if(s.equals(HETEROZYGOUS))
			{
			this.content=s;
			return;
			}
		if(s.indexOf('/')==-1) throw new IllegalArgumentException("Bad observation:"+s);
		this.content=s.toUpperCase().trim();
		}
	
	public Set<String> asSet()
		{
		Set<String> set= new HashSet<String>();
		for(String s:SPLIT.split(this.content))
			{
			set.add(s);
			}
		assert(set.size()>1);
		return set;
		}
	
	public boolean isInDel()
		{
		return asSet().contains("-");
		}
	
	public boolean isLargeDeletion()
		{
		return asSet().contains(LARGE_DELETION_FLAG);
		}
	
	/** returns true if the values contains HETEROZYGOUS */
	public boolean isHeterozygous()
		{
		if(this.content.equals(HETEROZYGOUS)) return true;
		return asSet().contains(HETEROZYGOUS);
		}
	
	public boolean isCompatibleWith(String observed)
		{
		Set<String> set=asSet();
		if(observed.length()==0 && set.contains("-")) return true;
		return set.contains(observed.toUpperCase());
		}
	
	public Observed reverseComplement()
		{
		String array[]=SPLIT.split(this.content);
		StringBuilder b=new StringBuilder();
		for(int i=0;i< array.length;++i)
			{
			if(i>0) b.insert(0,"/");
			String s= array[i];
			if(s.equals("-"))
				{
				b.insert(0,"-");
				}
			else if(s.equals(LARGE_DELETION_FLAG))
				{
				b.insert(0,LARGE_INSERTION_FLAG);
				}
			else if(s.equals(LARGE_INSERTION_FLAG))
				{
				b.insert(0,LARGE_DELETION_FLAG);
				}
			else
				{
				if(!BASES.matcher(s).matches()) throw new IllegalArgumentException("bad observed "+asString());
				b.insert(0,AcidNucleicUtils.reverseComplement(s));
				}
			}
		return new Observed(b.toString());
		}
	
	public char iupac()
		{
		Set<String> set= asSet();
		if(set.size()==2)
			{
			if(set.contains("A") && set.contains("G")) return 'R';
			if(set.contains("C") && set.contains("T")) return 'Y';
			if(set.contains("C") && set.contains("G")) return 'S';
			if(set.contains("A") && set.contains("T")) return 'W';
			if(set.contains("G") && set.contains("T")) return 'K';
			if(set.contains("A") && set.contains("C")) return 'M';
			return 'N';
			}
		else if(set.size()==3)
			{
			if(set.contains("C") && set.contains("G")&& set.contains("T")) return 'B';
			if(set.contains("A") && set.contains("G")&& set.contains("T")) return 'D';
			if(set.contains("A") && set.contains("C")&& set.contains("T")) return 'H';
			if(set.contains("A") && set.contains("C")&& set.contains("G")) return 'V';
			return 'N';
			}
		return 'N';
		}

	@Override
	public int hashCode()
		{
		final int prime = 31;
		int result = 1;
		result = prime * result + ((content == null) ? 0 : content.hashCode());
		return result;
		}

	@Override
	public boolean equals(Object obj)
		{
		if (this == obj) return true;
		if (obj == null) return false;
		if (!(obj instanceof Observed)) return false;
		Observed other = (Observed) obj;
		return content.equalsIgnoreCase(other.content);
		}
	
	public String asString()
		{
		return this.content;
		}
	
	@Override
	public String toString()
		{
		return asString();
		}
	}
